# BeanPropertyQueryMapper.java

    package org.codefilarete.stalactite.engine;

    import java.sql.ResultSet;
    import java.util.function.BiConsumer;

    import org.codefilarete.reflection.Mutator;
    import org.codefilarete.reflection.SerializableMutator;
    import org.codefilarete.stalactite.query.api.Selectable;
    import org.codefilarete.stalactite.query.model.Query;
    import org.codefilarete.stalactite.sql.result.BeanRelationFixer;
    import org.codefilarete.stalactite.sql.result.ResultSetRowAssembler;
    import org.codefilarete.stalactite.sql.result.ResultSetRowTransformer;
    import org.codefilarete.stalactite.sql.result.WholeResultSetTransformer.AssemblyPolicy;
    import org.codefilarete.tool.function.Converter;

    /**
     * Methods that define bean property mapping when creating an SQL query through {@link PersistenceContext#newQuery(Query, Class)}.
     *
     * @author Guillaume Mary
     */
    public interface BeanPropertyQueryMapper<C> {

    	/**
    	 * Maps a column to a bean property
    	 *
    	 * @param columnName column name that will fill the property
    	 * @param setter property setter
    	 * @param columnType column and value type
    	 * @param <I> column and value type
    	 * @return an instance that allows method chaining
    	 * @see #map(String, SerializableMutator, Converter)
    	 */
    	<I> BeanPropertyQueryMapper<C> map(String columnName, Mutator<C, I> setter, Class<I> columnType);

    	/**
    	 * Equivalent of {@link #map(String, Mutator, Class)} with an additional converter.
    	 * Maps a column to a bean property by converting its value before setting it.
    	 *
    	 * @param columnName column name that will fill the property
    	 * @param setter property setter
    	 * @param columnType column and value type
    	 * @param converter value converter
    	 * @param <I> column and value type
    	 * @return an instance that allows method chaining
    	 * @see #map(String, SerializableMutator, Converter)
    	 */
    	<I, J> BeanPropertyQueryMapper<C> map(String columnName, SerializableMutator<C, J> setter, Class<I> columnType, Converter<I, J> converter);

    	/**
    	 * Equivalent of {@link #map(String, Mutator, Class)} without ensuring column type argument : it will be deduced from setter.
    	 * Prefer {@link #map(String, Mutator, Class)} to ensure value reading from {@link ResultSet}
    	 *
    	 * @param columnName column name that will fill the property
    	 * @param setter property setter
    	 * @param <I> column and value type
    	 * @return an instance that allows method chaining
    	 */
    	<I> BeanPropertyQueryMapper<C> map(String columnName, SerializableMutator<C, I> setter);

    	/**
    	 * Equivalent of {@link #map(String, SerializableMutator, Class, Converter)} without ensuring column type argument : it will be deduced from setter.
    	 * Prefer {@link #map(String, SerializableMutator, Class, Converter)} to ensure value reading from {@link ResultSet}
    	 *
    	 * @param columnName column name that will fill the property
    	 * @param setter property setter
    	 * @param converter value converter
    	 * @param <I> column and value type
    	 * @return an instance that allows method chaining
    	 */
    	<I, J> BeanPropertyQueryMapper<C> map(String columnName, SerializableMutator<C, J> setter, Converter<I, J> converter);

    	/**
    	 * Equivalent of {@link #map(String, SerializableMutator)} with column argument.
    	 *
    	 * @param column column name that will fill the property
    	 * @param setter property setter
    	 * @param <I> column and value type
    	 * @return an instance that allows method chaining
    	 */
    	<I> BeanPropertyQueryMapper<C> map(Selectable<I> column, Mutator<C, I> setter);

    	/**
    	 * Equivalent of {@link #map(String, SerializableMutator, Converter)} with column argument.
    	 *
    	 * @param column column name that will fill the property
    	 * @param setter property setter
    	 * @param <I> column and value type
    	 * @return an instance that allows method chaining
    	 */
    	<I, J> BeanPropertyQueryMapper<C> map(Selectable<I> column, Mutator<C, J> setter, Converter<I, J> converter);

    	/**
    	 * Associates beans created by this instance and the ones created by another converter with setter (represented as a {@link BiConsumer}).
    	 * This allows to create bean graphs.
    	 *
    	 * @param combiner setter (on beans created by this instance) to fix beans created by given converter
    	 * @param relatedBeanCreator creator of other beans from a {@link ResultSet}
    	 * @param <V> type of beans created by given converter
    	 * @return this
    	 */
    	<K, V> BeanPropertyQueryMapper<C> map(BeanRelationFixer<C, V> combiner, ResultSetRowTransformer<V, K> relatedBeanCreator);

    	/**
    	 * Adds a low level {@link ResultSet} transformer, for cases where mapping methods are insufficient.
    	 * Assembly will occur on each row ({@link ResultSetRowAssembler#assemble(Object, ResultSet)} will be call for each {@link ResultSet} row)
    	 *
    	 * @param assembler a low-level {@link ResultSet} transformer
    	 * @return this
    	 */
    	default BeanPropertyQueryMapper<C> map(ResultSetRowAssembler<C> assembler) {
    		return map(assembler, AssemblyPolicy.ON_EACH_ROW);
    	}

    	/**
    	 * Adds a low level {@link ResultSet} transformer, for cases where mapping methods are insufficient.
    	 * Be aware that any bean created by given assembler won't participate in cache, if this is required then one should implement
    	 * its own cache.
    	 *
    	 * @param assembler a generic combiner of a root bean and each {@link ResultSet} row
    	 * @param assemblyPolicy policy to decide if given assemble shall be invoked on each row or not
    	 * @return this
    	 */
    	BeanPropertyQueryMapper<C> map(ResultSetRowAssembler<C> assembler, AssemblyPolicy assemblyPolicy);

    	/**
    	 * Sets a value for the given parameter.
    	 * To be used if the query is a String and contains a named placeholder as ":paramName"
    	 *
    	 * @param paramName name of the parameter in the sql
    	 * @param value value for the parameter
    	 * @return this
    	 */
    	BeanPropertyQueryMapper<C> set(String paramName, Object value);

    	/**
    	 * Sets a value for the given parameter giving explicit binder type.
    	 * To be used if the query is a String and contains a named placeholder as ":paramName"
    	 *
    	 * @param paramName name of the parameter in the sql
    	 * @param value value for the parameter
    	 * @param valueType type for value {@link java.sql.PreparedStatement} binder
    	 * @return this
    	 */
    	<O> BeanPropertyQueryMapper<C> set(String paramName, O value, Class<? super O> valueType);

    	/**
    	 * Sets a value for the given parameter expected to be a multi-valued one (such as "in") giving values binder type.
    	 * To be used if the query is a String and contains a named placeholder as ":paramName"
    	 *
    	 * @param paramName name of the parameter in the sql
    	 * @param value value for the parameter
    	 * @param valueType type for values {@link java.sql.PreparedStatement} binder
    	 * @return this
    	 */
    	<O> BeanPropertyQueryMapper<C> set(String paramName, Iterable<O> value, Class<? super O> valueType);
    }